
#include "IHeader.h"

using namespace BWE;

IHeader::IHeader()
{
	orientation = Orientation_None;
	visible = true;
	spacing = 1;
	resizable = false;
	hoverIndex = -1;
	handle = -1;
	pressed = false;
	draging = false;
	show_begin = -1;
	show_end = -1;
}
IHeader::~IHeader()
{

}

void IHeader::correctHandle()
{
	if (handle < 0)
		handle = 0;
	if (handle >= sections.size())
		handle = sections.size() - 1;
}
BRect IHeader::handleRect(int index)
{
	int handleSize = bMax(spacing, 5);
	BRect rect;
	if (!sections.check(index))
		return rect;
	if (sections[index].policy == Policy_None)
		return rect;
	if (orientation == Orientation_Horizontal)
	{
		rect = sections[index].rect;
		int cx = rect.right() + spacing / 2;
		rect.left() = cx - handleSize / 2;
		rect.right() = cx + handleSize / 2;
	}
	if (orientation == Orientation_Vertical)
	{
		rect = sections[index].rect;
		int cy = rect.bottom() + spacing / 2;
		rect.top() = cy - handleSize / 2;
		rect.bottom() = cy + handleSize / 2;
	}
	return rect;
}
BRange IHeader::xrange(int minx, int maxx)
{
	BRange range(sections.size());
	for (int i = 0; i < sections.size(); i++)
	{
		if (minx < sections[i].rect.right())
		{
			range.min() = i;
			while (i++ < sections.size())
			{
				if (maxx < sections[i].rect.left())
				{
					range.max() = i;
					return range;
				}
			}
		}
	}
	return range;
}
BRange IHeader::yrange(int miny, int maxy)
{
	BRange range(sections.size());
	for (int i = 0; i < sections.size(); i++)
	{
		if (miny < sections[i].rect.bottom())
		{
			range.min() = i;
			while (i++ < sections.size())
			{
				if (maxy < sections[i].rect.top())
				{
					range.max() = i;
					return range;
				}
			}
		}
	}
	return range;
}

int IHeader::sectionUnderPoint(const BPoint& point)
{
	for (int i = 0; i < sections.size(); i++)
	{
		if (sections[i].rect.contain(point))
			return i;
	}
	return -1;
}
int IHeader::handleUnderPoint(const BPoint& point)
{
	for (int i = 0; i < sections.size(); i++)
	{
		if (sections[i].policy == Policy_None)
			continue;
		BRect rect = handleRect(i);
		if (rect.contain(point))
			return i;
	}
	return -1;
}
void IHeader::distributeWidth(int width)
{
	int totalWidth = 0;
	int validCount = 0;
	for (int i = 0; i < sections.size(); i++)
	{
		IHeaderSection& section = sections[i];
		totalWidth += section.realSize.width() + spacing;
		section.finished = !section.visible || section.policy <= Policy_Fixed || section.stretch == 0.0f;
		if (section.finished)
			continue;
		validCount++;
	}
	if (validCount == 0)
		return;
	totalWidth -= spacing;
	int remainWidth = width - totalWidth;
	while (remainWidth != 0)
	{
		float totalStretch = 0;
		for (int i = 0; i < sections.size(); i++)
		{
			IHeaderSection& section = sections[i];
			if (section.finished)
				continue;
			if (remainWidth > 0 && !(section.policy & Policy_Expanding))
			{
				section.finished = true;
				continue;
			}
			if (remainWidth < 0 && !(section.policy & Policy_Shrinking))
			{
				section.finished = true;
				continue;
			}
			totalStretch += section.stretch;
		}
		if (totalStretch < 0.00001)
			break;

		int used = 0;
		for (int i = 0; i < sections.size(); i++)
		{
			IHeaderSection& section = sections[i];
			if (section.finished)
				continue;
			int width = (int)(section.stretch / totalStretch * remainWidth);
			if (width == 0)
				continue;
			used += width;
			section.realSize.width() += width;
		}
		if (used == 0)
			break;
		remainWidth -= used;
	}
	while (remainWidth > 0)
	{
		int used = 0;
		for (int i = 0; i < sections.size(); i++)
		{
			IHeaderSection& section = sections[i];
			if (section.finished)
				continue;
			int expanding = section.policy & Policy_Expanding;
			if (!expanding)
				continue;
			section.realSize.width() += 1;
			remainWidth--;
			used++;
			if (remainWidth < 1)
				break;
		}
		if (used == 0)
			break;
	}
}
void IHeader::distributeHeight(int height)
{
	int totalHeight = 0;
	int validCount = 0;
	for (int i = 0; i < sections.size(); i++)
	{
		IHeaderSection& section = sections[i];
		totalHeight += section.realSize.height() + spacing;
		section.finished = !section.visible || section.policy <= Policy_Fixed || section.stretch == 0.0f;
		if (section.finished)
			continue;
		validCount++;
	}
	if (validCount == 0)
		return;
	totalHeight -= spacing;
	int remainHeight = height - totalHeight;
	remainHeight -= spacing;
	while (remainHeight != 0)
	{
		float totalStretch = 0;
		for (int i = 0; i < sections.size(); i++)
		{
			IHeaderSection& section = sections[i];
			if (section.finished)
				continue;
			if (remainHeight > 0 && !(section.policy & Policy_Expanding))
			{
				section.finished = true;
				continue;
			}
			if (remainHeight < 0 && !(section.policy & Policy_Shrinking))
			{
				section.finished = true;
				continue;
			}
			totalStretch += section.stretch;
		}
		if (totalStretch < 0.00001)
			break;

		int used = 0;
		for (int i = 0; i < sections.size(); i++)
		{
			IHeaderSection& section = sections[i];
			if (section.finished)
				continue;
			int height = (int)(section.stretch / totalStretch * remainHeight);
			if (height == 0)
				continue;
			used += height;
			section.realSize.height() += height;
		}
		if (used == 0)
			break;
		remainHeight -= used;
	}
	while (remainHeight > 0)
	{
		int used = 0;
		for (int i = 0; i < sections.size(); i++)
		{
			IHeaderSection& section = sections[i];
			if (section.finished)
				continue;
			int expanding = section.policy & Policy_Expanding;
			if (!expanding)
				continue;
			section.realSize.height() += 1;
			remainHeight--;
			used++;
			if (remainHeight < 1)
				break;
		}
		if (used == 0)
			break;
	}
}

bool IHeader::dragBegin(const BPoint& pos)
{
	if (handle >= 0)
	{
		draging = true;
		pressedPoint = pos;
		pressedSize = sections[handle].realSize;
		return true;
	}
	return false;
}
bool IHeader::drag(const BPoint& pos)
{
	if (orientation == Orientation_Horizontal)
	{
		int xchange = pos.x() - pressedPoint.x();
		if (xchange == 0)
			return false;
		sections[handle].realSize = pressedSize;
		sections[handle].realSize += xchange;
		if (sections[handle].realSize.width() < 1)
			sections[handle].realSize.width() = 1;
		sections[handle].policy = Policy_Fixed;
		return true;
	}
	if (orientation == Orientation_Vertical)
	{
		int ychange = pos.y() - pressedPoint.y();
		if (ychange == 0)
			return false;
		sections[handle].realSize = pressedSize;
		sections[handle].realSize += ychange;
		if (sections[handle].realSize.height() < 1)
			sections[handle].realSize.height() = 1;
		sections[handle].policy = Policy_Fixed;
		return true;
	}
	return false;
}
void IHeader::paint(BPainter& painter)
{
	BRect clip = painter.clip();
	for (int i = 0; i < sections.size(); i++)
	{
		IHeaderSection& section = sections[i];
		if (!section.visible)
			continue;
		if (section.rect.bottom() < clip.top())
			continue;
		if (section.rect.top() > clip.bottom())
			break;
		if (section.policy != Policy_None)
		{
			StyleRole colorRole = Color_Handle;
			if (i == handle)
			{
				if (draging)
					colorRole = Color_Handle_Pressed;
				else
					colorRole = Color_Handle_Hovered;
			}
			if (painter.setColor(Color_Handle))
				painter.fillRect(handleRect(i));
		}
	}
	for (int i = 0; i < sections.size(); i++)
	{
		IHeaderSection& section = sections[i];
		if (!section.visible)
			continue;
		if (section.rect.bottom() < clip.top())
			continue;
		if (section.rect.top() > clip.bottom())
			break;
		painter.setClip(section.rect);
		State state = State_Normal;
		StyleRole textRole = Color_Text;
		StyleRole headerRole = Color_Header;
		StyleRole arrowColorRole = Color_Arrow;
		if (hoverIndex == i)
		{
			if (pressed)
			{
				state = State_Pressed;
				textRole = Color_Text_Pressed;
				headerRole = Color_Header_Pressed;
				arrowColorRole = Color_Arrow_Pressed;
			}
			else
			{
				state = State_Hovered;
				textRole = Color_Text_Hovered;
				headerRole = Color_Header_Hovered;
				arrowColorRole = Color_Arrow_Hovered;
			}
		}
		if (painter.setColor(headerRole))
			painter.fillRect(section.rect);
		if (section.text.size() && painter.setColor(textRole))
		{
			if (section.t_text.size())
				painter.drawText(section.ia_textRect, section.t_text);
			else
				painter.drawText(section.ia_textRect, section.text);
		}
		if (section.sortMode)
		{
			if (section.sortMode < 0)
			{
				if (upIcon)
				{
					BImage* image = upIcon->image(state);
					painter.drawImage(section.sortUpRect, image, true);
				}
				else
				{
					painter.setColor(arrowColorRole);
					painter.setLineSmooth(true);
					painter.drawGraph(section.sortUpRect, Graph_Arrow_Up_Fill);
				}
			}
			else
			{
				if (downIcon)
				{
					BImage* image = downIcon->image(state);
					painter.drawImage(section.sortDownRect, image, true);
				}
				else
				{
					painter.setColor(arrowColorRole);
					painter.setLineSmooth(true);
					painter.drawGraph(section.sortDownRect, Graph_Arrow_Down_Fill);
				}
			}
		}
	}
}

